package com.biyu.monitormanage.service.impl;

import com.biyu.monitormanage.common.exception.BizException;
import com.biyu.monitormanage.common.feign.AdminFeignService;
import com.biyu.monitormanage.common.utils.*;
import com.biyu.monitormanage.dao.MachineDao;
import com.biyu.monitormanage.dao.PoliceDao;
import com.biyu.monitormanage.entity.MachineEntity;
import com.biyu.monitormanage.entity.PoliceEntity;
import com.biyu.monitormanage.enums.MonitorParamEnums;
import com.biyu.monitormanage.enums.MonitorStatusEnums;
import com.biyu.monitormanage.enums.WrongEnums;
import com.biyu.monitormanage.model.bo.PoliceBo;
import com.biyu.monitormanage.model.bo.PoliceListBo;
import com.biyu.monitormanage.model.dto.RealDataLogDto;
import com.biyu.monitormanage.model.dto.RealTimeDataDto;
import com.biyu.monitormanage.model.request.RealDataLogRequest;
import com.biyu.monitormanage.service.EmailService;
import com.biyu.monitormanage.service.MessageService;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.biyu.monitormanage.dao.RealTimeDataDao;
import com.biyu.monitormanage.entity.RealTimeDataEntity;
import com.biyu.monitormanage.service.RealTimeDataService;


/**
 * @author 15491
 */
@Service("temHumService")
public class RealTimeDataServiceImpl extends ServiceImpl<RealTimeDataDao, RealTimeDataEntity> implements RealTimeDataService {

    private static final String MACHINE_ID = "machine_id";

    private final MachineDao machineDao;
    private final RealTimeDataDao realTimeDataDao;
    private final PoliceDao policeDao;
    private final EmailService emailService;
    private final ThreadPoolExecutor executor;
    private final MessageService messageService;
    private final AdminFeignService adminFeignService;

    @Autowired
    public RealTimeDataServiceImpl(MachineDao machineDao,
                                   RealTimeDataDao realTimeDataDao,
                                   PoliceDao policeDao,
                                   EmailService service,
                                   ThreadPoolExecutor executor,
                                   MessageService messageService,
                                   AdminFeignService adminFeignService) {
        this.machineDao = machineDao;
        this.realTimeDataDao = realTimeDataDao;
        this.policeDao = policeDao;
        this.emailService = service;
        this.executor = executor;
        this.messageService = messageService;
        this.adminFeignService = adminFeignService;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<RealTimeDataEntity> page = this.page(
                new Query<RealTimeDataEntity>().getPage(params),
                new QueryWrapper<RealTimeDataEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageAllOfList(Map<String, Object> params) {
        // 1、查所有的温湿度数据
        List<RealTimeDataEntity> temHumEntityList = realTimeDataDao.selectList(null);
        if (Objects.isNull(temHumEntityList)) {
            throw new BizException(WrongEnums.RESULT_NULL.getCode(), WrongEnums.RESULT_NULL.getMsg());
        }
        // 2、过滤创建时间
        List<RealTimeDataDto> realTimeDataDtoList =  temHumEntityList.stream().map(realTimeDataEntity -> {
            Date createAt = realTimeDataEntity.getCreateAt();
            // 转换成String类型
            String date = DateFormatUtils.exchangeDate(createAt);
            String machineId = realTimeDataEntity.getMachineId();
            // 3、根据机器id查询机器信息
            QueryWrapper<MachineEntity> queryWrapper = new QueryWrapper<>();
            MachineEntity machineEntity = machineDao.selectOne(queryWrapper.eq(MACHINE_ID, machineId));
            if (Objects.isNull(machineEntity)) {
                return null;
            }
            // TODO 前端表格添加字段
            return RealTimeDataDto.builder()
                    .id(realTimeDataEntity.getId())
                    .department(machineEntity.getDepartment())
                    .humidity(realTimeDataEntity.getHumidity())
                    .temperature(realTimeDataEntity.getTemperature())
                    .smokeSensor(realTimeDataEntity.getSmokeSensor())
                    .infraRed(realTimeDataEntity.getInfraRed())
                    .waterLeakage(realTimeDataEntity.getWaterLeakage())
                    .machineName(machineEntity.getMachineName())
                    .userId(machineEntity.getUserId())
                    .createAt(date)
                    .machinePosition(machineEntity.getMachinePosition())
                    .machineId(machineEntity.getMachineId())
                    .build();
        }).filter(Objects::nonNull).collect(Collectors.toList());
        // 4、封装到dto中
        return new PageUtils(realTimeDataDtoList, new Query<RealTimeDataDto>().getPage(params));
    }

    @Override
    public List<RealDataLogDto> queryLogForRealData(RealDataLogRequest request) {
        // 1、
        return null;
    }

    @Override
    public boolean saveAndPolice(RealTimeDataEntity realTimeDataEntity) {

        // 0、保存数据
        this.save(realTimeDataEntity);

        // 1、查报警设置里面 启用的阈值数据
        List<PoliceEntity> policeEntities = policeDao.queryUsing();
        if (CollectionUtils.isEmpty(policeEntities)) {
            System.out.println("查报警设置里面 启用的阈值数据为空");
            return false;
        }
        List<PoliceEntity> tempPoliceParam;
        PoliceListBo policeListBo = new PoliceListBo(realTimeDataEntity.getMachineId());
        // 2、将查询到的预警数组，按照参数转换为map
        Map<String, List<PoliceEntity>> policeMap = policeEntities.stream().collect(Collectors.groupingBy(PoliceEntity::getParamKey));
        // 3、判断当前参数 用实时数据和阈值比较 
            // 3.1、温度
        if (Objects.nonNull(tempPoliceParam = policeMap.get(MonitorParamEnums.TEMPERATURE.getParamName())) && Objects.nonNull(realTimeDataEntity.getTemperature())) {
            tempPoliceParam.forEach(entity -> {
                float temPolice = Float.parseFloat(entity.getParamVal());
                Float temReal = realTimeDataEntity.getTemperature();
                if (temReal > temPolice || Objects.equals(temReal, temPolice)) {
                    // 报警
                    policeListBo.add(entity.getPoliceType(), PoliceBo.builder().paramKey(MonitorParamEnums.TEMPERATURE.getDesc())
                                                                                .realVal(temReal.toString())
                                                                                 .build(), entity.getId());
                    policeDao.updateStatus(entity.getId(), MonitorStatusEnums.TURN_DOWN.getCode());
                }
            });
        }
            // 3.2、湿度
        if (Objects.nonNull(tempPoliceParam = policeMap.get(MonitorParamEnums.HUMIDITY.getParamName())) && Objects.nonNull(realTimeDataEntity.getHumidity())) {
            tempPoliceParam.forEach(police -> {
                float humPolice = Float.parseFloat(police.getParamVal());
                Float humidityReal = realTimeDataEntity.getHumidity();
                if (humidityReal > humPolice || Objects.equals(humidityReal, humPolice)) {
                    // 报警
                    policeListBo.add(police.getPoliceType(), PoliceBo.builder()
                                    .paramKey(MonitorParamEnums.HUMIDITY.getDesc())
                                    .realVal(humidityReal.toString())
                            .build(), police.getId());
                    policeDao.updateStatus(police.getId(), MonitorStatusEnums.TURN_DOWN.getCode());
                }
            });
        }
            // 3.3、烟雾
        if (Objects.nonNull(tempPoliceParam = policeMap.get(MonitorParamEnums.SMOKE_SENSOR.getParamName())) && Objects.nonNull(realTimeDataEntity.getSmokeSensor())) {
            tempPoliceParam.forEach(police -> {
                int smokeStatus = Integer.parseInt(police.getParamVal());
                if (Objects.equals(smokeStatus, MonitorStatusEnums.DANGER.getCode())) {
                    // 报警
                    policeListBo.add(police.getPoliceType(), PoliceBo.builder()
                                    .paramKey(MonitorParamEnums.SMOKE_SENSOR.getDesc())
                                    .realVal("出现异常")
                            .build(), police.getId());
                    policeDao.updateStatus(police.getId(), MonitorStatusEnums.TURN_DOWN.getCode());
                }
            });
        }
            // 3.4、水浸
        if (Objects.nonNull(tempPoliceParam = policeMap.get(MonitorParamEnums.WATER_LEAKAGE.getParamName())) && Objects.nonNull(realTimeDataEntity.getWaterLeakage())) {
            tempPoliceParam.forEach(police -> {
                int water = Integer.parseInt(police.getParamVal());
                if (Objects.equals(water, MonitorStatusEnums.DANGER.getCode())) {
                    // 报警
                    policeListBo.add(police.getPoliceType(), PoliceBo.builder()
                                    .paramKey(MonitorParamEnums.WATER_LEAKAGE.getDesc())
                                    .realVal("出现异常")
                            .build(), police.getId());
                    policeDao.updateStatus(police.getId(), MonitorStatusEnums.TURN_DOWN.getCode());
                }
            });
        }
            // 3.5、红外
        if (Objects.nonNull(tempPoliceParam = policeMap.get(MonitorParamEnums.INFRA_RED.getParamName())) && Objects.nonNull(realTimeDataEntity.getInfraRed())) {
            tempPoliceParam.forEach(police -> {
                int inf = Integer.parseInt(police.getParamVal());
                if (Objects.equals(inf, MonitorStatusEnums.DANGER.getCode())) {
                    // 报警
                    policeListBo.add(police.getPoliceType(), PoliceBo.builder()
                                    .paramKey(MonitorParamEnums.INFRA_RED.getDesc())
                                    .realVal("出现异常")
                            .build(), police.getId());
                    policeDao.updateStatus(police.getId(), MonitorStatusEnums.TURN_DOWN.getCode());
                }
            });
        }
        if (CollectionUtils.isEmpty(policeListBo.getMsgPolice()) && CollectionUtils.isEmpty(policeListBo.getMailPolice())) {
            return false;
        }
        // 异步报警
        return asyncPoliceToUser(policeListBo);
    }

    /**
     * 异步报警
     * @param policeListBo 封装好的报警数据
     * @return 是否报警成功
     */
    private boolean asyncPoliceToUser(PoliceListBo policeListBo) {

        String machineId = policeListBo.getMachineId();
        QueryWrapper<MachineEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("machine_id", machineId);
        MachineEntity machineEntity = machineDao.selectOne(queryWrapper);
        if (Objects.isNull(machineEntity)) {
            throw new BizException(WrongEnums.RESULT_NULL.getCode(), "异步报警-查询机器号为空");
        }
        // 拼装机器名
        String machineName = MachineUtils.getMachineName(machineEntity);

        // 邮件报警
        CompletableFuture<Void> mailFuture = CompletableFuture.runAsync(() -> {
            String mailComment = PoliceUtils.getComment(policeListBo.getMailPolice()).fromMail(machineName);
            // 邮件
            emailService.sendSimpleMail("15613893739@163.com","系统告警邮件", mailComment);
            System.out.println(Thread.currentThread().getName() + "yi fa song email" + mailComment);
        }, executor).whenComplete((res, th) -> {
            if (Objects.nonNull(th)) {
                throw new BizException(WrongEnums.POLICE_ECE.getCode(), "邮件报警失败");
            }
        });

        // 短信报警
        CompletableFuture<Void> msgFuture = CompletableFuture.runAsync(() -> {
            String[] templateParamSet = PoliceUtils.getComment(policeListBo.getMsgPolice()).fromMessage(machineName);
            // 手机号
            messageService.sendMessage(templateParamSet, new String[]{"+8613014326979"});
            System.out.println(Thread.currentThread().getName() + "短信报警");
        }, executor).whenComplete((res, th) -> {
            if (Objects.nonNull(th)) {
                throw new BizException(WrongEnums.POLICE_ECE.getCode(), "短信报警失败");
            }
        });

        mailFuture.runAfterBothAsync(msgFuture, () -> {
            try {
                // 恢复时间
                Thread.sleep(60 * 1000);
                System.out.println("恢复");
                //恢复全部报警状态
                policeListBo.getIdList().forEach( policeId -> {
                    policeDao.updateStatus(policeId, MonitorStatusEnums.SAFE.getCode());
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
                throw new BizException(WrongEnums.THREAD.getCode(), "等待恢复报警状态时的线程睡眠异常");
            }
        }, executor);
        return true;
    }


}